/*
 *   Copyright (c) 2018. 刘路 All rights reserved
 *   版权所有 刘路 并保留所有权利 2018.
 *   ===============================================================
 *   这不是一个自由软件！您只能在不用于商业目的的前提下对程序代码进行修改和
 *   使用。不允许对程序代码以任何形式任何目的的再发布。如果项目发布携带作者
 *   认可的特殊 LICENSE 则按照 LICENSE 执行，废除上面内容。请保留原作者信息。
 *   ================================================================
 *   刘路（feedback@zhoyq.com）于 2018. 创建
 *   http://zhoyq.com
 */

package com.zhoyq.helper;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jsoup.helper.StringUtil;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.awt.*;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Random;

/**
 * 机密解密 摘要等算法
 * @author 刘路
 */
public class Code {
    /**
     * 根据指定参数值返回随机颜色   
     * @param fc 颜色区间开始值
     * @param bc 颜色区间结束值
     * @return 返回随机颜色
     */
    public static Color randomColor(int fc,int bc){
        Random random = new Random();
        int max = 255;
        if( fc > max ){ fc = max; }
        if( bc>max ){ bc = max; }
        //设置个0-255之间的随机颜色值
        int r=fc+random.nextInt(bc - fc);
        int g=fc+random.nextInt(bc - fc);
        int b=fc+random.nextInt(bc - fc);
        // 返回具有指定红色、绿色和蓝色值的不透明的 sRGB 颜色
        return new Color(r,g,b);
    }

    /**
     * md5 摘要
     * @param text 摘要消息
     * @return 摘要
     */
    public static String md5(String text) throws NoSuchAlgorithmException {
        byte[] b = md5(text.getBytes());
        text = ByteArrHelper.toHexString(b);
        return text;
    }

    /**
     * md5 摘要
     * @param data 摘要消息（字节码）
     * @return 摘要（字节码）
     */
    private static byte[] md5(byte[] data) throws NoSuchAlgorithmException {
        MessageDigest md;
        md = MessageDigest.getInstance("MD5");
        md.update(data);
        return md.digest();
    }

    /**
     * hash-mac-Md5 摘要
     * @param key 加密密钥
     * @param data 加密消息
     * @return 加密字符串
     */
    public static String hmacMd5(String key,String data) throws NoSuchAlgorithmException {
        return ByteArrHelper.toHexString(hmacMd5(key.getBytes(),data.getBytes()));
    }

    /**
     * hash-mac-Md5 摘要
     *
     * HmacMd5 calculation formula: H(K XOR oPad, H(K XOR iPad, text)) HmacMd5
     * 计算公式：H(K XOR oPad, H(K XOR iPad, text))
     * H 代表hash算法，本类中使用MD5算法，K代表密钥，text代表要加密的数据 iPad为0x36，oPad为0x5C。
     *
     * @param key 加密密钥 （字节码）
     * @param data 加密消息 （字节码）
     * @return 加密字节码
     */
    private static byte[] hmacMd5(byte[] key,byte[] data) throws NoSuchAlgorithmException {
        int length = 64;
        byte[] iPad = new byte[length];
        byte[] oPad = new byte[length];
        for (int i = 0; i < length; i++) {
            iPad[i] = 0x36;
            oPad[i] = 0x5C;
        }
        // 实际的key
        byte[] actualKey = key;
        // 长度64
        byte[] keyArr = new byte[length];
        // 如果密钥长度，大于64字节，就使用哈希算法，计算其摘要，作为真正的密钥。
        if (key.length > length) {
            actualKey = md5(key);
        }
        System.arraycopy(actualKey, 0, keyArr,0, actualKey.length);
        // 如果密钥长度不足64字节，就使用0x00补齐到64字节。
        if (actualKey.length < length) {
            for (int i = actualKey.length; i < keyArr.length; i++){
                keyArr[i] = 0x00;
            }
        }
        // 使用密钥和 iPad 进行异或运算。
        byte[] kiPadXorResult = new byte[length];
        for (int i = 0; i < length; i++) {
            kiPadXorResult[i] = (byte) (keyArr[i] ^ iPad[i]);
        }
        // 将待加密数据追加到K XOR iPad 计算结果后面
        byte[] firstAppendResult = new byte[kiPadXorResult.length + data.length];
        System.arraycopy(kiPadXorResult, 0, firstAppendResult, 0, kiPadXorResult.length);
        System.arraycopy(data, 0, firstAppendResult, kiPadXorResult.length, data.length);
        // 使用哈希算法计算上面结果的摘要。
        byte[] firstHashResult = md5(firstAppendResult);
        // 使用密钥和 oPad 进行异或运算。
        byte[] koPadXorResult = new byte[length];
        for (int i = 0; i < length; i++) {
            koPadXorResult[i] = (byte) (keyArr[i] ^ oPad[i]);
        }
        // 将H(K XOR iPad, text)结果追加到K XOR opad结果后面
        byte[] secondAppendResult = new byte[koPadXorResult.length + firstHashResult.length];
        System.arraycopy(koPadXorResult, 0, secondAppendResult, 0, koPadXorResult.length);
        System.arraycopy(firstHashResult, 0, secondAppendResult, koPadXorResult.length, firstHashResult.length);
        // H(K XOR oPad, H(K XOR iPad, text)) 对上面的数据进行哈希运算。
        return md5(secondAppendResult);
    }

    /**
     * aes cbc pkcs5 加密
     * @param mKey 密钥
     * @param vector 向量
     * @param data 数据
     * @return 加密后字节码
     */
    public static byte[] aesCbcPkcs5Encode(byte[] mKey,byte[] vector,byte[] data){
        return aesEncode(mKey,vector,AESModel.AES_CBC_PKCS5Padding,data);
    }
    /**
     * aes cbc pkcs5 解密
     * @param mkey
     * @param vector
     * @param data
     * @return
     */
    public static final byte[] aesCbcPkcs5Decode(byte[] mkey,byte[] vector,byte[] data){
        return aesDecode(mkey,vector,AESModel.AES_CBC_PKCS5Padding,data);
    }

    /**
     * aes 加密
     * @param mkey
     * @param vector
     * @param model
     * @param data
     * @return
     */
    private static byte[] aesEncode(byte[] mkey,byte[] vector,AESModel model, byte[] data) {
        String modelStr = model.getValue();
        try {
            // 创建密码器
            Cipher cipher = Cipher.getInstance(modelStr);
            SecretKey skeySpec = new SecretKeySpec(mkey, "AES");
            if(model==AESModel.AES_CBC_PKCS5Padding){
                if(vector==null){
                    vector = new byte[]{ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
                }
                // 初始化
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec,new IvParameterSpec(vector));
            } else {
                // 初始化
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            }
            byte[] result = cipher.doFinal(data);
            // 加密
            return result;
        } catch (Exception e) { }
        return null;
    }

    /**
     * aes解密
     * @param mkey
     * @param vector
     * @param model
     * @param data
     * @return
     */
    private static byte[] aesDecode(byte[] mkey,byte[] vector,AESModel model,byte[] data) {
        String modelStr = model.getValue();
        try {
            Cipher cipher = Cipher.getInstance(modelStr);
            SecretKeySpec skeySpec = new SecretKeySpec(mkey, "AES");
            if(model==AESModel.AES_CBC_PKCS5Padding){
                if(vector==null) {
                    vector = new byte[]{ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
                }
                // 初始化
                cipher.init(Cipher.DECRYPT_MODE, skeySpec,new IvParameterSpec(vector));
            } else  {
                // 初始化
                cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            }
            byte[] result = cipher.doFinal(data);
            return result;
        } catch (Exception e) { }
        return null;
    }

    /**
     * sha1 摘要
     * @param text
     * @return
     */
    public static String sha1(String text){
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA-1");
        } catch (NoSuchAlgorithmException e) { }
        md.update(text.getBytes());
        byte[] b = md.digest();
        text = ByteArrHelper.toHexString(b);
        return text;
    }

    /**
     * sha224 摘要
     * @param text
     * @return
     */
    public static String sha224(String text){
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA-224");
        } catch (NoSuchAlgorithmException e) { }
        md.update(text.getBytes());
        byte[] b = md.digest();
        text = ByteArrHelper.toHexString(b);
        return text;
    }

    /**
     * sha256 摘要
     * @param text
     * @return
     */
    public static String sha256(String text){
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException e) { }
        md.update(text.getBytes());
        byte[] b = md.digest();
        text = ByteArrHelper.toHexString(b);
        return text;
    }
    /**
     * sha384 摘要
     * @param text
     * @return
     */
    public static String sha384(String text){
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA-384");
        } catch (NoSuchAlgorithmException e) { }
        md.update(text.getBytes());
        byte[] b = md.digest();
        text = ByteArrHelper.toHexString(b);
        return text;
    }

    /**
     * sha512 摘要
     * @param text
     * @return
     */
    public static String sha512(String text){
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA-512");
        } catch (NoSuchAlgorithmException e) { }
        md.update(text.getBytes());
        byte[] b = md.digest();
        text = ByteArrHelper.toHexString(b);
        return text;
    }

    /**
     * base64加密
     * @param data
     * @return
     */
    public static byte[] base64Encode(byte[] data){
        return Base64.encodeBase64(data);
    }

    /**
     * base64加密
     * @param data
     * @return
     */
    public static String base64StringEncode(byte[] data){
        return Base64.encodeBase64String(data);
    }

    /**
     * base64解密
     * @param data
     * @return
     */
    public static byte[] base64Decode(byte[] data){
        return Base64.decodeBase64(data);
    }

    /**
     * base64解密
     * @param str
     * @return
     */
    public static byte[] base64Decode(String str){
        return Base64.decodeBase64(str);
    }

    /**
     * 获取字符
     * @return
     */
    private static char[] getChar(){
        char[] passwordLit = new char[62];
        char fword = 'A';
        char mword = 'a';
        char bword = '0';
        for (int i = 0; i < 62; i++) {
            if (i < 26) {
                passwordLit[i] = fword;
                fword++;
            }else if(i<52){
                passwordLit[i] = mword;
                mword++;
            }else{
                passwordLit[i] = bword;
                bword++;
            }
        }
        return passwordLit;
    }

    /**
     * 生成随机数
     * @param len
     * @return
     */
    public static String generate(Integer len){
        char[] r = getChar();
        Random rr = new Random();
        char[] pw= new char[len];
        for(int i=0;i<pw.length;i++){
            int num = rr.nextInt(62);
            pw[i]=r[num];
        }
        return new String(pw);
    }


    public static KeyPair genRSAKeyPair(int keySize){
        KeyPair keyPair = null;
        try {
            KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
            gen.initialize(keySize);
            keyPair = gen.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {  }
        return keyPair;
    }

    /**
     * 公钥加密
     * @param data
     * @param keyBytes
     * @return
     */
    public static byte[] rsaEncodeByPublicKey(byte[] data,byte[] keyBytes){
        try {
            // 取得公钥
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory;
            keyFactory = KeyFactory.getInstance("RSA");
            Key publicKey = keyFactory.generatePublic(x509KeySpec);

            // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            return cipher.doFinal(data);
        } catch ( Exception e) { }
        return null;
    }

    // 公钥解密
    public static byte[] rsaDecodeByPublicKey(byte[] data,byte[] keyBytes){
        try {
            // 取得公钥
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Key publicKey = keyFactory.generatePublic(x509KeySpec);

            // 对数据解密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, publicKey);

            return cipher.doFinal(data);
        } catch ( Exception e) { }
        return null;
    }

    // 私钥加密
    public static byte[] rsaEncodeByPrivateKey(byte[] data,byte[] keyBytes){
        try {
            // 取得私钥
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

            // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);

            return cipher.doFinal(data);
        } catch ( Exception e) { }
        return null;
    }

    // 私钥解密
    public static byte[] rsaDecodeByPrivateKey(byte[] data,byte[] keyBytes){
        try {
            // 取得私钥
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

            // 对数据解密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            return cipher.doFinal(data);
        } catch ( Exception e) { }
        return null;
    }

    /**
     * rsa签名
     * @param data
     * @param keyBytes
     * @return
     */
    public static byte[] rsaSign(byte[] data,byte[] keyBytes){
        try{
            // 构造PKCS8EncodedKeySpec对象
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

            // KEY_ALGORITHM 指定的加密算法
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            // 取私钥匙对象
            PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

            // 用私钥对信息生成数字签名
            Signature signature = Signature.getInstance("MD5withRSA");
            signature.initSign(priKey);
            signature.update(data);
            return signature.sign();
        }catch(Exception e){}
        return null;
    }

    /**
     * rsa验证
     * @param data
     * @param keyBytes
     * @param sign
     * @return
     */
    public static boolean rsaVerify(byte[] data,byte[] keyBytes, byte[] sign){
        try{
            // 构造X509EncodedKeySpec对象
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

            // KEY_ALGORITHM 指定的加密算法
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            // 取公钥匙对象
            PublicKey pubKey = keyFactory.generatePublic(keySpec);

            Signature signature = Signature.getInstance("MD5withRSA");
            signature.initVerify(pubKey);
            signature.update(data);

            // 验证签名是否正常
            return signature.verify(sign);
        }catch(Exception e){}
        return false;
    }

//    public static byte[] rsaEncodeByPublicKeyNoLimit(byte[] data,byte[] publicKey,int len){
//        Integer pos = 0;
//        byte[] res = new byte[0];
//        while(pos!=data.length){
//            byte[] dataBuf = null;
//            if(pos+len > data.length){
//                dataBuf = ArraysUtils.subByte(data,pos,data.length);
//                pos = data.length;
//            }else{
//                dataBuf = ArraysUtils.subByte(data,pos,pos+len);
//                pos += len;
//            }
//            res = ArraysUtils.union(res,rsaEncodeByPublicKey(dataBuf,publicKey));
//        }
//        return res;
//    }
//
//    public static byte[] rsaDecodeByPrivateKeyNoLimit(byte[] data,byte[] privateKey,int len){
//        Integer pos = 0;
//        byte[] res = new byte[0];
//        while(pos!=data.length){
//            byte[] dataBuf = null;
//            if(pos+len > data.length){
//                dataBuf = ArraysUtils.subByte(data,pos,data.length);
//                pos = data.length;
//            }else{
//                dataBuf = ArraysUtils.subByte(data,pos,pos+len);
//                pos += len;
//            }
//            res = ArraysUtils.union(res,rsaEncodeByPublicKey(dataBuf,publicKey));
//        }
//        return res;
//    }


    /**
     * 使用base64配合提取显示
     */
    public static class KeyMap{
        private String publicKey;
        private String privateKey;
        public String getPublicKey() {
            return publicKey;
        }
        public void setPublicKey(String publicKey) {
            this.publicKey = publicKey;
        }
        public String getPrivateKey() {
            return privateKey;
        }
        public void setPrivateKey(String privateKey) {
            this.privateKey = privateKey;
        }

    }

    public static KeyMap genRSAKeyMap(int keySize){
        KeyMap keyMap = null;
        try {
            KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
            gen.initialize(keySize);
            KeyPair keyPair = gen.generateKeyPair();
            keyMap = new KeyMap();
            keyMap.setPrivateKey(base64StringEncode(keyPair.getPrivate().getEncoded()));
            keyMap.setPublicKey(base64StringEncode(keyPair.getPublic().getEncoded()));
        } catch (NoSuchAlgorithmException e) {  }
        return keyMap;
    }

    /**
     * 公钥加密
     * @param data
     * @param publicKeyStr
     * @return
     */
    public static byte[] rsaEncodeByPublicKeywithBase64(byte[] data,String publicKeyStr){
        try {
            byte[] keyBytes = base64Decode(publicKeyStr);
            // 取得公钥
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory;
            keyFactory = KeyFactory.getInstance("RSA");
            Key publicKey = keyFactory.generatePublic(x509KeySpec);

            // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            return cipher.doFinal(data);
        } catch ( Exception e) { }
        return null;
    }

    /**
     * 公钥解密
     * @param data
     * @param publicKeyStr
     * @return
     */
    public static byte[] rsaDecodeByPublicKey(byte[] data,String publicKeyStr){
        try {
            byte[] keyBytes = base64Decode(publicKeyStr);
            // 取得公钥
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Key publicKey = keyFactory.generatePublic(x509KeySpec);

            // 对数据解密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, publicKey);

            return cipher.doFinal(data);
        } catch ( Exception e) { }
        return null;
    }

    /**
     * 私钥加密
     * @param data
     * @param privateKeyStr
     * @return
     */
    public static byte[] rsaEncodeByPrivateKey(byte[] data,String privateKeyStr){
        try {
            byte[] keyBytes = base64Decode(privateKeyStr);
            // 取得私钥
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

            // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);

            return cipher.doFinal(data);
        } catch ( Exception e) { }
        return null;
    }

    /**
     * 私钥解密
     * @param data
     * @param privateKeyStr
     * @return
     */
    public static byte[] rsaDecodeByPrivateKey(byte[] data,String privateKeyStr){
        try {
            byte[] keyBytes = base64Decode(privateKeyStr);
            // 取得私钥
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

            // 对数据解密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            return cipher.doFinal(data);
        } catch ( Exception e) { }
        return null;
    }

    /**
     * 私钥签名
     * @param data
     * @param privateKeyStr
     * @return
     */
    public static byte[] rsaSign(byte[] data,String privateKeyStr){
        try{
            byte[] keyBytes = base64Decode(privateKeyStr);
            // 构造PKCS8EncodedKeySpec对象
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

            // KEY_ALGORITHM 指定的加密算法
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            // 取私钥匙对象
            PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

            // 用私钥对信息生成数字签名
            Signature signature = Signature.getInstance("MD5withRSA");
            signature.initSign(priKey);
            signature.update(data);
            return signature.sign();
        }catch(Exception e){}
        return null;
    }

    /**
     * 公钥验证
     * @param data
     * @param publicKeyStr
     * @param sign
     * @return
     */
    public static boolean rsaVerify(byte[] data,String publicKeyStr, String sign){
        try{
            byte[] keyBytes = base64Decode(publicKeyStr);
            // 构造X509EncodedKeySpec对象
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

            // KEY_ALGORITHM 指定的加密算法
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            // 取公钥匙对象
            PublicKey pubKey = keyFactory.generatePublic(keySpec);

            Signature signature = Signature.getInstance("MD5withRSA");
            signature.initVerify(pubKey);
            signature.update(data);

            // 验证签名是否正常
            return signature.verify(base64Decode(sign));
        }catch(Exception e){}
        return false;
    }

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static String sm3(String text){
        byte[] hash = sm3(text.getBytes());
        return ByteArrHelper.toHexString(hash);
    }

    public static String sm3(String key, String text){
        byte[] hash = sm3(key.getBytes(), text.getBytes());
        return ByteArrHelper.toHexString(hash);
    }

    private static byte[] sm3(byte[] text){
        SM3Digest digest = new SM3Digest();
        digest.update(text, 0, text.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return hash;
    }

    private static byte[] sm3(byte[] key, byte[] text){
        KeyParameter keyParameter = new KeyParameter(key);
        SM3Digest digest = new SM3Digest();
        HMac mac = new HMac(digest);
        mac.init(keyParameter);
        digest.update(text, 0, text.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return hash;
    }

    public static String genSm4Key(int size) throws NoSuchProviderException, NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("SM4", BouncyCastleProvider.PROVIDER_NAME);
        keyGenerator.init(size, new SecureRandom());
        return ByteArrHelper.toHexString(keyGenerator.generateKey().getEncoded());
    }

    public static String sm4Encode(String key, String data) throws NoSuchPaddingException,
            NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
        Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS5Padding");
        Key sm4Key = new SecretKeySpec(StringHelper.hexStr2bytes(key), "SM4");
        cipher.init(Cipher.ENCRYPT_MODE, sm4Key);
        byte[] byteRes = cipher.doFinal(data.getBytes());
        return ByteArrHelper.toHexString(byteRes);
    }

    public static String sm4Decode(String key, String data) throws NoSuchPaddingException,
            NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
        Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS5Padding");
        Key sm4Key = new SecretKeySpec(StringHelper.hexStr2bytes(key), "SM4");
        cipher.init(Cipher.DECRYPT_MODE, sm4Key);
        byte[] byteRes = cipher.doFinal(StringHelper.hexStr2bytes(data));
        return new String(byteRes);
    }

}
